<!--
 * @Author: rxn 1003312535@qq.com
 * @Date: 2024-07-05 15:25:53
 * @LastEditors: rxn 1003312535@qq.com
 * @LastEditTime: 2024-08-07 15:03:38
 * @FilePath: \vue3-progect\src\views\example\three\geometry\index.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<!--缓存几何-->
<template>
	<div id="map1"></div>
	<div id="tooltip"></div>
</template>

<script setup>
import * as THREE from "three";
import {
	OrbitControls
	// MapControls
} from "three/addons/controls/OrbitControls.js";
import {
	CSS2DRenderer,
	CSS2DObject
} from "three/addons/renderers/CSS2DRenderer.js";
import TWEEN from "@tweenjs/tween.js"; //1. tweenjs创建threejs动画
import * as d3 from "d3";
import { onMounted } from "vue";

onMounted(() => {
	let container = document.getElementById("map1");
	const obj = new ChinaMap(container, { axesHelper: true });
	obj.FileLoader();
	// obj.createPlane();
});
class ChinaMap {
	constructor(container, option = {}) {
		this.container = container;
		this.option = option;
		this.offsetXY = d3.geoMercator();
		this.init();
	}
	init() {
		this.scene = new THREE.Scene();
		this.setCamera();
		this.setRenderer();
		// const controls = new MapControls(this.camera, this.renderer.domElement);
		this.setRaycaster();

		this.animate();

		this.initHelper(); //辅助功能
		this.otherConfig(); //灯光
		this.windowChange(); //窗口变化
		const downInstance = new DownLoadPicture({
			renderer: this.renderer,
			container: this.container
		});
	}
	createPlane() {
		const geometry = new THREE.PlaneGeometry(100, 100);
		const material = new THREE.MeshBasicMaterial({ color: 0xaaaaaa });
		const mesh = new THREE.Mesh(geometry, material);
		mesh.name = "背景";
		this.scene.add(mesh);
	}
	windowChange() {
		// onresize 事件会在窗口被调整大小时发生
		window.onresize = () => {
			// 重置渲染器输出画布canvas尺寸
			this.container = document.getElementById("map1");
			this.renderer.setSize(
				this.container.offsetWidth,
				this.container.offsetHeight
			);
			this.labelRenderer.setSize(
				this.container.offsetWidth,
				this.container.offsetHeight
			);
			// 全屏情况下：设置观察范围长宽比aspect为窗口宽高比
			this.camera.aspect =
				this.container.offsetWidth / this.container.offsetHeight;
			// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
			// 但是不会每渲染一帧，就通过相机的属性计算投影矩阵(节约计算资源)
			// 如果相机的一些属性发生了变化，需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
			this.camera.updateProjectionMatrix();
		};
	}
	otherConfig() {
		this.setAmientLight();

		const directionalLight = new THREE.DirectionalLight(0xe8eaeb, 0.2);
		directionalLight.position.set(0, 10, 15);
		const directionalLight2 = directionalLight.clone();
		directionalLight2.position.set(-10, 10, 5);
		const directionalLight3 = directionalLight.clone();
		directionalLight3.position.set(5, 20, 20);
		const directionalLight4 = directionalLight.clone();
		directionalLight4.position.set(-5, 20, 40);
		this.scene.add(directionalLight);
		this.scene.add(directionalLight2);
		this.scene.add(directionalLight3);
		this.scene.add(directionalLight4);
		// const helper = new THREE.DirectionalLightHelper(directionalLight, 5);
		// const helper1 = new THREE.DirectionalLightHelper(directionalLight4, 5);
		// const helper2 = new THREE.DirectionalLightHelper(directionalLight2, 5);
		// const helper3 = new THREE.DirectionalLightHelper(directionalLight3, 5);
		// this.scene.add(helper);
		// this.scene.add(helper1);
		// this.scene.add(helper2);
		// this.scene.add(helper3);
	}
	setCamera() {
		// const width = this.container.offsetWidth; //canvas画布宽度
		// const height = this.container.offsetHeight; //canvas画布高度
		// const k = width / height; //canvas画布宽高比
		// const s = 50; //控制left, right, top, bottom范围大小
		// this.camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 8000);
		// this.camera.position.set(0, -20, 5);
		// return;
		this.camera = new THREE.PerspectiveCamera(
			90,
			this.container.offsetWidth / this.container.offsetHeight,
			0.1,
			1000
		);
		// this.camera.up.set(0, -1, 0);
		this.camera.position.set(0, -5, 10);
	}
	setRenderer() {
		this.renderer = new THREE.WebGLRenderer();
		this.renderer.setSize(
			this.container.offsetWidth,
			this.container.offsetHeight
		);
		// this.renderer.setClearAlpha(0.0); //改变背景透明度值
		this.container.appendChild(this.renderer.domElement);

		this.labelRenderer = new CSS2DRenderer();
		this.labelRenderer.domElement.style.position = "absolute";
		this.labelRenderer.domElement.style.top = "0px";
		this.labelRenderer.domElement.style.pointerEvents = "none";
		this.labelRenderer.setSize(
			this.container.offsetWidth,
			this.container.offsetHeight
		);
		this.container.appendChild(this.labelRenderer.domElement);
	}
	setAmientLight() {
		this.ambientLight = new THREE.AmbientLight(0xd4e7fd, 4);
		this.scene.add(this.ambientLight);
	}
	animate() {
		// console.log(this.mouse, "1");
		TWEEN.update();
		requestAnimationFrame(this.animate.bind(this));
		this.render();
	}
	render() {
		this.renderer.render(this.scene, this.camera);
		this.labelRenderer.render(this.scene, this.camera);
	}

	FileLoader() {
		const loader = new THREE.FileLoader();

		//加载一个文本文件，并把结果输出到控制台上
		loader.load(
			// resource URL
			// "/lib/cn_100000.json",
			"/lib/cn_100000_copy.json",

			// onLoad回调
			(data) => {
				// console.log(JSON.parse(data));
				this.mapWrap = new THREE.Object3D();
				this.mapWrap.name = "地图整体";
				this.map = this.createMap(JSON.parse(data));
				this.mapWrap.add(this.map);
				this.scene.add(this.mapWrap);
				this.setCenter(this.mapWrap);
				// console.log(this.map.children, "this.map");
				for (let i = 0; i < this.map.children.length - 1; i++) {
					// if (Math.random() - 0.2 > 0) continue;
					let arr = this.map.children;
					if (
						/\d+$/gi.test(arr[i].properties.adcode) &&
						/\d+$/gi.test(arr[i + 1].properties.adcode)
					) {
						// console.log(
						// 	arr[i].properties.name,
						// 	arr[i].properties.adcode,
						// 	arr[i + 1].properties.name,
						// 	arr[i + 1].properties.adcode
						// );
						let prevItem = {
							center: this.offsetXY(
								arr[i].properties.centroid || arr[i].properties.center
							),
							depth: arr[i].depth
						};
						let nextItem = {
							center: this.offsetXY(
								arr[i + 1].properties.centroid || arr[i + 1].properties.center
							),
							depth: arr[i + 1].depth
						};
						const path = new flyLine();
						path.createCatmullRomCurve3([prevItem, nextItem]);
						//-
						const line = path.createLine();
						this.scene.add(line);
						//-
						this.flyLine = path.createFlyLine();
						this.scene.add(this.flyLine);
						//-
						const ShaderLine = path.createShaderLine();
						// this.scene.add(ShaderLine);
						// //-
						// const textureLine = path.createTextureLine();
						// this.textureLine = textureLine.clone();
						// this.textureLine.geometry = textureLine.geometry;
						// this.scene.add(this.textureLine);
						// this.createCatmullRomCurve3([prevItem, nextItem]);
					}
				}
			},

			// onProgress回调
			function (xhr) {
				// console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
			},

			// onError回调
			function (err) {
				console.error("An error happened");
			}
		);
	}
	//创建地图
	createMap(data) {
		const map = new THREE.Object3D();
		map.name = "地图";
		const _this = this;
		const center = data.features[0].properties.centroid;
		console.log(center, "center");
		this.offsetXY.center(center).translate([0, 0]);
		data.features.forEach((feature) => {
			const unit = new THREE.Object3D();
			const { coordinates, type } = feature.geometry;
			const { name, center, centroid, adcode } = feature.properties;
			unit.properties = feature.properties;
			const color = new THREE.Color(`hsl(
      ${233},
      ${Math.random() * 30 + 55}%,
      ${Math.random() * 30 + 55}%)`).getHex();
			const depth = Math.random() + 0.4;
			unit.depth = depth;
			unit.name = feature.properties.name;
			const label = _this.createLabel(name, centroid, depth);
			const icon = _this.createIcon(center, depth);
			coordinates.forEach((coordinate) => {
				if (type === "MultiPolygon") coordinate.forEach((item) => fn(item));
				if (type === "Polygon") fn(coordinate);
				function fn(coordinate) {
					const mesh = _this.createMesh(coordinate, color, depth);
					const { downLine, upLine } = _this.createLine(coordinate, depth);
					unit.add(mesh, downLine, upLine);
					// unit.add(mesh);
				}
			});
			unit.add(label, icon);
			// unit.add(icon);
			map.add(unit);
			this.scene.add(icon);
		});

		return map;
	}
	// offsetXY() {
	// 	// 墨卡托投影转换
	// 	//d3.geoMercator()是一个地理投影函数，用于将地球表面的经纬度坐标映射到二维平面上。
	// 	//.center(center)是用于指定投影的中心点。这个中心点决定了投影的中心位置，地图上的所有要素都将以该点为中心进行投影转换。
	// 	//.translate([0, 0])是指定投影的平移量。这里的 [0, 0] 表示在平面坐标系中的 x 和 y 方向上都没有平移，也就是将地图的投影结果放置在平面坐标系的原点位置。
	// 	return d3.geoMercator().center([106.41995, 40.18994]).translate([0, 0]);
	// }
	createMesh(data, color, depth) {
		const shape = new THREE.Shape();
		data.forEach((item, idx) => {
			const [x, y] = this.offsetXY(item);
			// console.log(x, y, "x");
			if (idx === 0) shape.moveTo(x, -y);
			else shape.lineTo(x, -y);
		});
		const extrudeSettings = {
			depth: depth,
			bevelEnabled: false, //挤出的形状应用是否斜角
			color: color,
			emissive: 0x000000,
			roughness: 0.45,
			metalness: 0.8,
			transparent: true,
			side: false
		};
		const shapeGeometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
		const shapematerial = new THREE.MeshStandardMaterial({
			color: color,
			emissive: 0x000000,
			roughness: 0.45,
			metalness: 0.8,
			transparent: true,
			side: true
		});

		const mesh = new THREE.Mesh(shapeGeometry, shapematerial);
		return mesh;
	}
	createLine(data, depth) {
		const lineGeometry = new THREE.BufferGeometry();
		let arr = [];
		data.forEach((item, idx) => {
			const [x, y] = this.offsetXY(item);
			arr.push(x, -y, 0);
		});
		const vertices = new Float32Array(arr);
		const attribute = new THREE.BufferAttribute(vertices, 3);
		lineGeometry.setAttribute("position", attribute);

		const downLineMaterial = new THREE.LineBasicMaterial({
			color: "#3480C4",
			transparent: true
			// opacity: 0.1
		});
		const upLineMaterial = new THREE.LineBasicMaterial({
			color: "#3480C4",
			transparent: true
			// opacity: 0.1
		});

		const downLine = new THREE.Line(lineGeometry, downLineMaterial);
		const upLine = new THREE.Line(lineGeometry, upLineMaterial);

		downLine.position.z = -0.0001;
		upLine.position.z = depth + 0.0001;
		return { downLine, upLine };
	}
	//设置射线
	setRaycaster() {
		this.raycaster = new THREE.Raycaster();
		this.mouse = new THREE.Vector2();
		this.tooltip = document.getElementById("tooltip");
		let intersect = null;
		const onMouseMove = (event) => {
			// console.log(event.clientX, event.clientY, "event");
			// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
			this.mouse.x = (event.offsetX / this.container.offsetWidth) * 2 - 1;
			this.mouse.y = -(event.offsetY / this.container.offsetHeight) * 2 + 1;

			// 通过摄像机和鼠标位置更新射线
			this.raycaster.setFromCamera(this.mouse, this.camera);
			// 算出射线 与当场景相交的对象有那些
			const intersects = this.raycaster
				.intersectObjects(this.scene.children, true)
				.filter((item) => item.object.type != "Line");
			// console.log("射线扫描到的对象：", intersects);

			if (intersects.length > 0) {
				if (intersects[0].object.type === "Mesh") {
					if (intersect) isAplha(intersect, 1);
					intersect = intersects[0].object.parent;
					isAplha(intersect, 0.4);
				}
				if (intersects[0].object.type === "Sprite") {
					// console.log(intersects[0].object);
				}
			} else {
				if (intersect) isAplha(intersect, 1);
			}
			function isAplha(intersect, opacity) {
				intersect.children.forEach((item) => {
					if (item.type === "Mesh") {
						item.material.opacity = opacity;
					}
				});
			}

			// 更改div位置
			this.tooltip.style.left = event.offsetX + 2 + "px";
			this.tooltip.style.top = event.offsetY + 2 + "px";
			this.showTip();
			// console.log(this.mouse, "this.mouse");
		};
		const onClick = (event) => {
			console.log(event.clientX, event.clientY, "event");
			// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
			this.mouse.x = (event.offsetX / this.container.offsetWidth) * 2 - 1;
			this.mouse.y = -(event.offsetY / this.container.offsetHeight) * 2 + 1;
			// 通过摄像机和鼠标位置更新射线,// 形象点说就是在点击位置创建一条射线，射线穿过的模型代表选中
			this.raycaster.setFromCamera(this.mouse, this.camera);
			// 算出射线 与当场景相交的对象有那些
			const intersects = this.raycaster
				.intersectObjects(this.scene.children, true)
				.filter((item) => item.object.type != "Line");
			console.log("射线器返回的对象", intersects);
		};
		this.renderer.domElement.addEventListener("click", onClick, false);
	}
	//创建文字
	createLabel(name, point, depth) {
		// console.log(point, "point");
		if (!point) return "";
		const div = document.createElement("div");
		div.style.color = "#fff";
		div.style.fontSize = "12px";
		div.style.textShadow = "1px 1px 2px #047cd6";
		div.textContent = name;
		const label = new CSS2DObject(div);
		label.scale.set(0.01, 0.01, 0.01);
		const [x, y] = this.offsetXY(point || [0, 0]);
		label.position.set(x, -y, depth);
		return label;
	}
	//创建图标
	createIcon(point, depth) {
		const url = new URL("@/assets/image/map/location.png", import.meta.url)
			.href;
		const iconURL = new THREE.TextureLoader().load(url);
		const material = new THREE.SpriteMaterial({
			map: iconURL,
			transparent: true,
			color: 0xfff000
		});
		const sprite = new THREE.Sprite(material);
		const [x, y] = this.offsetXY(point || [0, 0]);
		sprite.scale.set(0.3, 0.3, 0.3);
		sprite.position.set(x, -y, depth + 0.2);
		sprite.renderOrder = 1;
		// console.log(url, map, "url");
		return sprite;
	}
	showTip() {
		// 显示省份的信息
		if (this.lastPick) {
			const properties = this.lastPick.object.parent.properties;

			this.tooltip.textContent = properties.name;

			this.tooltip.style.visibility = "visible";
		} else {
			this.tooltip.style.visibility = "hidden";
		}
	}

	/**
	 * ---辅助功能
	 */
	//初始化辅助功能
	initHelper() {
		// this.option.axesHelper && this.AxesHelper();
		!this.option.OrbitControlsHelper && this.OrbitControlsHelper();
		// this.cameraHelper();
	}
	//坐标轴
	AxesHelper() {
		const axesHelper = new THREE.AxesHelper(200);
		this.scene.add(axesHelper);
	}
	// 相机轨道运动
	OrbitControlsHelper() {
		const controls = new OrbitControls(this.camera, this.renderer.domElement);
		// controls.enableRotate = false;
		controls.minPolarAngle = Math.PI * 0.5;
		controls.maxPolarAngle = Math.PI * 0.75; //默认值Math.PI
		// 左右旋转范围
		controls.minAzimuthAngle = -Math.PI / 4;
		controls.maxAzimuthAngle = Math.PI / 4;

		controls.update();
	}
	// 相机辅助线
	cameraHelper() {
		const cameraHelper = new THREE.CameraHelper(this.camera);
		this.scene.add(cameraHelper);
	}
	//模拟3维包围盒 Box3 的辅助对象.
	setCenter(map) {
		// map.rotation.x = -Math.PI / 2;
		const box = new THREE.Box3().setFromObject(map);
		const size = box.getSize(new THREE.Vector3()); // 计算包围盒尺寸
		const center = box.getCenter(new THREE.Vector3()); // 计算包围盒中心坐标
		const offset = [0, 0];
		map.position.x = map.position.x - center.x - offset[0];
		// map.position.z = map.position.z - center.z - offset[1];
		const helper = new THREE.Box3Helper(box, 0xffffff);
		// console.log("模型size", size);
		// console.log("模型中心坐标", center);
		// this.scene.add(helper);
	}
	/**
	 * 实现飞线轨迹
	 *
	 */
	createCatmullRomCurve3(data) {
		const [startCenterX, startCenterY] = this.offsetXY(data[0].center);
		const startDepth = data[0].depth;
		const [endCenterX, endCenterY] = this.offsetXY(data[1].center);
		const endDepth = data[1].depth;
		// p1、p2轨迹线起始点坐标
		const p1 = new THREE.Vector3(startCenterX, -startCenterY, startDepth);
		const p2 = new THREE.Vector3(endCenterX, -endCenterY, endDepth);
		// console.log(p1, p2);
		// 计算p1和p3的中点坐标
		const x = (p2.x + p1.x) / 2;
		const y = (p2.y + p1.y) / 2;
		const z = (endDepth + startDepth) / 2 + 1;
		const p = new THREE.Vector3(x, y, z);

		const arr = [p1, p, p2];
		// 三维样条曲线
		const curve = new THREE.CatmullRomCurve3(arr);
		const curveArr = curve.getPoints(50);
		const geometry = new THREE.BufferGeometry();
		geometry.setFromPoints(curveArr);
		const material = new THREE.LineBasicMaterial({
			color: 0xffffff
		});
		const lineMesh = new THREE.Line(geometry, material);
		this.mapWrap.add(lineMesh);
	}
}
/**
 * -------------------------------------------------------
 * 飞线
 *
 */
class flyLine {
	curve = null;
	constructor(container) {}
	/**
	 * 创建曲线
	 * start array 开始坐标
	 * end array 结束坐标
	 * depth object 弧线高度 {方向：高度}， {x:20},{y:20},{z:200}
	 */
	createCatmullRomCurve3(data) {
		const [startCenterX, startCenterY] = data[0].center;
		const startDepth = data[0].depth;
		const [endCenterX, endCenterY] = data[1].center;
		const endDepth = data[1].depth;
		// p1、p2轨迹线起始点坐标
		const p1 = new THREE.Vector3(startCenterX, -startCenterY, startDepth);
		const p2 = new THREE.Vector3(endCenterX, -endCenterY, endDepth);
		const x = (p2.x + p1.x) / 2;
		const y = (p2.y + p1.y) / 2;
		const z = (endDepth + startDepth) / 2 + 1;
		const p = new THREE.Vector3(x, y, z);

		const arr = [p1, p, p2];
		// 三维样条曲线
		this.curve = new THREE.CatmullRomCurve3(arr);
	}
	//-创建连线
	createLine(segment = 50) {
		const points = this.curve.getPoints(segment);
		const geometry = new THREE.BufferGeometry();
		geometry.setFromPoints(points);
		const material = new THREE.LineBasicMaterial({ color: 0x999999 });
		const lineMesh = new THREE.Line(geometry, material);
		return lineMesh;
	}
	//-创建飞线
	/**
	 * length num 多少个等间距
	 */
	createFlyLine(length = 5, segment = 200) {
		const points = this.curve.getSpacedPoints(segment);
		const slicePoints = points.slice(0, length);

		const geometry = new THREE.BufferGeometry();
		geometry.setFromPoints(slicePoints);
		// console.log(slicePoints, "slicePoints");
		// return;
		const colorArr = [];
		for (let i = 0; i < slicePoints.length; i++) {
			const color1 = new THREE.Color("#00FFFF"); // 线颜色
			const color2 = new THREE.Color("#FFFF00"); // 飞痕颜色
			// 飞痕渐变色
			let color = color1.lerp(color2, i / 5);
			colorArr.push(color.r, color.g, color.b);
		}
		const colorAttribute = new THREE.BufferAttribute(
			new Float32Array(colorArr),
			3
		);
		geometry.setAttribute("color", colorAttribute);
		geometry.attributes.position.needsUpdate = true;
		const material = new THREE.LineBasicMaterial({
			vertexColors: true
		});
		this.createFlyLineAnimate(geometry, points);
		const lineMesh = new THREE.Line(geometry, material);
		return lineMesh;
	}
	//-创建飞线动画
	createFlyLineAnimate(geometry, points) {
		// console.log(points.length, "points--动画");
		// 创建动画
		let tween = new TWEEN.Tween({ index: 0 })
			.to({ index: points.length }, this.cycle || 1000)
			.onUpdate(function (t) {
				let movedLineGeom = geometry;
				let id = Math.ceil(t.index);
				let pointsList = points.slice(id, id + 10); //从曲线上获取一段
				movedLineGeom && movedLineGeom.setFromPoints(pointsList);
				movedLineGeom.attributes.position.needsUpdate = true;
			})
			.repeat(Infinity);
		tween.start();
	}
	//-创建贴图功能
	createTextureLine() {
		const url = new URL("@/assets/image/flyLine/jiantou.png", import.meta.url);
		const textLoader = new THREE.TextureLoader();
		const texture = textLoader.load(url);
		texture.repeat.set(10, 2);
		texture.needsUpdate = true;
		// 设置.wrapS也就是U方向，纹理映射模式(包裹模式)
		texture.wrapS = THREE.RepeatWrapping; //对应offste.x偏移
		// 设置.wrapT也就是V方向，纹理映射模式
		texture.wrapT = THREE.RepeatWrapping; //对应offste.y偏移
		const geometry = new THREE.TubeGeometry(this.curve, 40, 1, 25);
		const material = new THREE.MeshLambertMaterial({
			side: true,
			color: 0xffffff,
			map: texture
		});
		this.createTextureLineAnimate(texture);
		const mesh = new THREE.Mesh(geometry, material);
		return mesh;
	}
	//-创建贴图动画
	createTextureLineAnimate(texture) {
		let tween = new TWEEN.Tween({ x: 0 })
			.to({ x: 100 }, 1000)
			.onUpdate(function (t) {
				texture.offset.x -= 0.01;
			})
			.repeat(Infinity);
		tween.start();
	}
	//-创建着色器
	createShaderLine(segment = 200) {
		const points = this.curve.getSpacedPoints(segment);
		let indexList = [];
		points.forEach((item, index) => {
			indexList.push(index);
		});
		const geometry = new THREE.BufferGeometry();
		geometry.setFromPoints(points);
		geometry.setAttribute(
			"aIndex",
			new THREE.Float32BufferAttribute(indexList, 1)
		);

		const vertexShader = `
    attribute float aIndex;
    uniform float uTime;
    uniform vec3 vColor;
    varying float vSize;

    void main() {
      gl_Position = projectionMatrix*modelViewMatrix* vec4(position,1.0);
      if(aIndex < uTime + 10.0 && aIndex > uTime - 10.0) {
        vSize = (aIndex + 5.0 - uTime) ;
      }else {
      }
      gl_PointSize = vSize;
    }
    `;
		const fragmentShader = `
        varying float vSize;
        uniform vec3 vColor;
        void main(){
            if(vSize<=0.0){
                gl_FragColor = vec4(1.0,0.0,0.0,0.0);
            }else{
                gl_FragColor = vec4(vColor,1.0);
            }

        }
      `;

		const material = new THREE.ShaderMaterial({
			vertexShader,
			fragmentShader,
			transparent: true, //允许透明
			side: true,
			vertexColors: true, //允许设置使用顶点颜色渲染
			uniforms: {
				uTime: { value: 0 },
				vColor: { value: new THREE.Color(0x00ffff) }
			}
		});
		this.createShaderLineAnimate(material);
		const mesh = new THREE.Points(geometry, material);
		return mesh;
	}
	//-创建着色器动画
	createShaderLineAnimate(material) {
		let tween = new TWEEN.Tween({ index: 0 })
			.to({ index: 200 }, 1000)
			.onUpdate(function (t) {
				// console.log(t, "t");
				let id = Math.ceil(t.index);
				// console.log(id, "id");
				material.uniforms.uTime.value = id;
			})
			.repeat(Infinity);
		tween.start();
	}
}
/**
 * 下载图片
 */
class DownLoadPicture {
	constructor(option = {}) {
		if (!option.container || !option.renderer)
			throw new Error("类DownLoadPicture-----参数container、 renderer 必传");
		this.container = option.container;
		this.renderer = option.renderer;
		this.suffix = option.suffix || "image/png";
		this.fileName = option.fileName || Date.now() + "png";
		if (option.template) {
		} else {
			this.createElBtn();
		}
		console.log(this.renderer, option.renderer, "-----");
	}
	createElBtn() {
		const btnEl = document.createElement("div");
		btnEl.textContent = "下载";
		btnEl.style =
			"position:absolute; right: 10px; top: 10px; color: #fff; cursor: pointer;";
		btnEl.onclick = this.saveFile.bind(this);
		this.container.appendChild(btnEl);
	}
	saveFile() {
		console.log("下载：", this, "downLoadBtn");
		const link = document.createElement("a");
		const canvas = this.renderer.domElement;
		link.href = canvas.toDataURL(this.suffix);
		link.download = this.fileName;
		link.click();
	}
}
</script>

<style lang="less" scoped>
#map1 {
	height: 100%;
}
#tooltip {
	position: absolute;
	z-index: 2;
	background: white;
	padding: 10px;
	border-radius: 2px;
	visibility: hidden;
}
</style>
